//http://www.riemers.net/eng/Tutorials/XNA/Csharp/series2d.phps
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace AndyPike.Experiments.XNA
{
    public class MyGame : Game
    {
        private readonly GraphicsDeviceManager graphics;
        private SpriteBatch spriteBatch;
        private Texture2D background;
        private Texture2D foreground;
        private int screenWidth;
        private int screenHeight;
        private Player[] players;
        private const int NUM_OF_PLAYERS = 4;
        private Texture2D carriage;
        private Texture2D cannon;
        private float playerScaling;
        private int currentPlayer;
        private SpriteFont font;
        private Texture2D rocket;
        private bool rocketFlying = false;
        private Vector2 rocketPosition;
        private Vector2 rocketDirection;
        private float rocketAngle;
        private float rocketScaling = 0.1f;
        private Texture2D smoke;
        private readonly List<Vector2> smokeList = new List<Vector2>();
        private readonly Random randomizer = new Random();
        int[] terrainContour;

        public MyGame()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = 500;
            graphics.PreferredBackBufferHeight = 500;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();

            Window.Title = "Andy's XNA Experiment";

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            background = Content.Load<Texture2D>("background");
            foreground = Content.Load<Texture2D>("foreground");
            carriage = Content.Load<Texture2D>("carriage");
            cannon = Content.Load<Texture2D>("cannon");
            font = Content.Load<SpriteFont>("myFont");
            rocket = Content.Load<Texture2D>("rocket");
            smoke = Content.Load<Texture2D>("smoke");

            screenWidth = GraphicsDevice.PresentationParameters.BackBufferWidth;
            screenHeight = GraphicsDevice.PresentationParameters.BackBufferHeight;
            playerScaling = 40.0f / carriage.Width; //Plateaus are 40px long
            
            SetUpPlayers();
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) Exit();

            ProcessKeyboard();
            UpdateRocket();

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();
            DrawScenery();
            DrawPlayers();
            DrawSmoke();
            DrawRocket();
            DrawText();
            spriteBatch.End();

            base.Draw(gameTime);
        }

        private void DrawScenery()
        {
            var rectangle = new Rectangle(0, 0, screenWidth, screenHeight);

            spriteBatch.Draw(background, rectangle, Color.White);
            spriteBatch.Draw(foreground, rectangle, Color.White);
        }

        private void SetUpPlayers()
        {
            var playerColors = new[]
                                   {
                                        Color.Red,
                                        Color.Green,
                                        Color.Blue,
                                        Color.Purple,
                                        Color.Orange,
                                        Color.Indigo,
                                        Color.Yellow,
                                        Color.SaddleBrown,
                                        Color.Tomato,
                                        Color.Turquoise
                                    };

            players = new Player[NUM_OF_PLAYERS];
            for (int i = 0; i < NUM_OF_PLAYERS; i++)
            {
                players[i].IsAlive = true;
                players[i].Color = playerColors[i];
                players[i].Angle = MathHelper.ToRadians(90);
                players[i].Power = 100;
            }

            players[0].Position = new Vector2(100, 193);
            players[1].Position = new Vector2(200, 212);
            players[2].Position = new Vector2(300, 361);
            players[3].Position = new Vector2(400, 164);
        }

        private void DrawPlayers()
        {
            foreach (Player player in players)
            {
                if (!player.IsAlive) continue;
                
                var xPos = (int)player.Position.X;
                var yPos = (int)player.Position.Y;
                var cannonOrigin = new Vector2(11, 50);

                spriteBatch.Draw(cannon, new Vector2(xPos + 20, yPos - 10), null, player.Color, player.Angle, cannonOrigin, playerScaling, SpriteEffects.None, 1);
                spriteBatch.Draw(carriage, player.Position, null, player.Color, 0, new Vector2(0, carriage.Height), playerScaling, SpriteEffects.None, 0);

            }
        }

        private void DrawRocket()
        {
            if (rocketFlying)
                spriteBatch.Draw(rocket, rocketPosition, null, players[currentPlayer].Color, rocketAngle, new Vector2(42, 240), 0.1f, SpriteEffects.None, 1);
        }

        private void DrawText()
        {
            Player player = players[currentPlayer];
            var currentAngle = (int)MathHelper.ToDegrees(player.Angle);
            
            spriteBatch.DrawString(font, "Cannon angle: " + currentAngle, new Vector2(20, 20), player.Color);
            spriteBatch.DrawString(font, "Cannon power: " + player.Power, new Vector2(20, 45), player.Color);
        }

        private void DrawSmoke()
        {
            foreach (Vector2 smokePos in smokeList)
            {
                spriteBatch.Draw(smoke, smokePos, null, Color.White, 0, new Vector2(40, 35), 0.2f, SpriteEffects.None, 1);
            }
        }

        private void ProcessKeyboard()
        {
            //Get the current keyboard state
            KeyboardState keyboard = Keyboard.GetState();
            
            //Change the angle of the cannon
            if (keyboard.IsKeyDown(Keys.Left))
                players[currentPlayer].Angle -= 0.01f;

            if (keyboard.IsKeyDown(Keys.Right))
                players[currentPlayer].Angle += 0.01f;

            //Ensure that the cannon is not pointing down (in either direction)
            if (players[currentPlayer].Angle > MathHelper.PiOver2)
                players[currentPlayer].Angle = -MathHelper.PiOver2;

            if (players[currentPlayer].Angle < -MathHelper.PiOver2)
                players[currentPlayer].Angle = MathHelper.PiOver2;

            //Allow the current player to change their cannon's power
            if (keyboard.IsKeyDown(Keys.Down))
                players[currentPlayer].Power -= 1;
            if (keyboard.IsKeyDown(Keys.Up))
                players[currentPlayer].Power += 1;
            if (keyboard.IsKeyDown(Keys.PageDown))
                players[currentPlayer].Power -= 20;
            if (keyboard.IsKeyDown(Keys.PageUp))
                players[currentPlayer].Power += 20;

            //Keep the power between 0 and 1000
            if (players[currentPlayer].Power > 1000)
                players[currentPlayer].Power = 1000;
            if (players[currentPlayer].Power < 0)
                players[currentPlayer].Power = 0;

            //Has the rocket been fired?
            if (keyboard.IsKeyDown(Keys.A) || keyboard.IsKeyDown(Keys.Space))
            {
                rocketFlying = true;
                rocketPosition = players[currentPlayer].Position;
                rocketPosition.X += 20;
                rocketPosition.Y -= 10;
                rocketAngle = players[currentPlayer].Angle;

                var up = new Vector2(0, -1);
                Matrix rotationMatrix = Matrix.CreateRotationZ(rocketAngle);
                rocketDirection = Vector2.Transform(up, rotationMatrix);
                rocketDirection *= players[currentPlayer].Power / 50.0f;
            }
        }

        private void UpdateRocket()
        {
            if (!rocketFlying) return;
            
            var gravity = new Vector2(0, 1);
            rocketDirection += gravity / 10.0f;
            rocketPosition += rocketDirection;
            rocketAngle = (float)Math.Atan2(rocketDirection.X, -rocketDirection.Y);

            for (int i = 0; i < 5; i++)
            {
                Vector2 smokePos = rocketPosition;
                smokePos.X += randomizer.Next(10) - 5;
                smokePos.Y += randomizer.Next(10) - 5;
                smokeList.Add(smokePos);
            }
        }

        //NEXT: http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2D/Manual_texture_creation.php
    }
}
